/**
 * author: hh2o4
 * author: shiyang
 * author: zyf
 */
#ifndef H_WFQQUEUE_H
#define H_WFQQUEUE_H

#include <map>
#include <queue>
#include <vector>
#include "ns3/tag.h"
#include "ns3/queue.h"
#include "ns3/socket.h"
#include "ns3/ipv4-header.h"
#include "ns3/udp-header.h"

namespace ns3 {

class H_WFQQueue : public Queue {
public:
  static TypeId GetTypeId(void);
  H_WFQQueue(uint8_t type = 0);
  virtual ~H_WFQQueue();

  /**
   * \the function is inherented from ns3::Queue, and is realized in wfq-in-netdevice.cc,
   * and the function is used to do the packet enqueue operation.
   *
   * \param item is the type of queue item corresponding to the packet that will push into the queue.
   *
   * \returns true if the packet is pushed into the queue without any error,
   * or it will return false if the packet can't be push into the queue.
   */
  virtual bool DoEnqueue(Ptr<QueueItem> item);
  
  /**
   * \the function is inherented from ns3:Queue, and is realized in wfq-in-netdevice.cc,
   * and it is used to do the packet dequeue operation.
   *
   * \returns a queue item that indicate the packet which has already go out of the queue,
   * or it will return an empty queue item.
   */
  virtual Ptr<QueueItem> DoDequeue(void);

  /**
   * \the function is called by H_WFQQueue::CreateQueueWithWeight,
   * which is used to create an empty inner queue of WFQ, 
   * and to do corresponding initial works, in order to change WFQ dynamically.
   */
  void CreateQueue(void);
  
  /**
   * \the function is used to create a certain queue with arranged weight.
   * 
   * \param weight is the weight value that is supposed to be arranged to the inner queue.
   */
  void CreateQueueWithWeight(uint32_t weight);

  /**
   * \the function is used to calculate the virtual finish time of the first packet in different inner queue,
   * when there's a packet just get out of queue.
   *
   * \param deqID is the id of inner queue that has just pop a packet out.
   */
  void ComputeFinishTime(uint32_t deqID);

  /**
   * \the function is used to provide an interface to ajust the inner queue number and weight dynamically.
   * 
   * \param weight is a vector which contains the weight value and queue number 
   * that is supposed to arrange to the WFQ.
   */
	bool SetQueue(std::vector<uint32_t> weight);
  
  /**
   * \the function is used to set the link rate data which is used in WFQ algorithm.
   * 
   * \param linkRate is the link rate value, which needs to equal to real link rate that used in simulation demo.
   */
  void SetLinkRate(uint64_t linkRate);

  /**
   * \the funciton is called by GetEnqID, and is used to get the tos value of a certain packet,
   * in order to get the id of the queue in which the packet is supposed to be pushed.
   *
   * \param item is corresponding to the packet
   *
   * \returns the tos value of the packet.
   */
  uint32_t GetTosValue(Ptr<QueueItem> item);
  
  /**
   * \the function is called by DoEnqueue, and is used to get the id of queue in which the packet is supposed to be pushed.
   * 
   * \param tosValue is the tos value of packets which is returned by GetTosValue.
   * 
   * \returns the id of queue in which the packet is supposed to be pushed.
   */
  uint32_t GetEnqID(uint32_t tosValue);
  
  /**
   * \the function is called by DoDequeue, 
   * which is used to get the id of queue that will pop packet out,
   * according to the virtual finish time of different inner queue.
   *
   * \returns the id of queue that will pop packet out this time. 
   */
  uint32_t GetDeqID(void);
  
  /**
   * \the function is not necessary to use,
   * just realize the inherent function of ns3::Queue.
   *
   * \returns the first packet of the first inner queue of WFQ.
   */
  Ptr<const QueueItem> DoPeek(void) const;
  
  /*
   *the function is used to set the matching rule from tos to enqID.
   *key of the map indicates the tos of application.
   *value of the map indecates the enqID which matching the tos.
   */
  void SetMap(std::map<uint8_t,uint8_t> map);

  /*
   *the function is used to set ecn threshold.
   */
  void SetThreshold(float threshold);

  /*
   *the function is used to set queue size limit.
   */
  void SetLimit(uint32_t limit);

	/**
   * \the function is used to get link rate value that used in WFQ algorithm
   *
   * \returns the value of link rate that arranged by function SetLinkRate.
   */
	uint64_t GetLinkRate();

  /**
   * \the variable is the entity of WFQ queue.
   */
  std::vector<std::queue<Ptr<QueueItem> > >  m_packets;

  /**
   * \the variable is vector that indicate the weight value of different inner queue,
   * according to the index of this vector..
   */
  std::vector<uint32_t> m_weight;

private:
  
  /**
   * \the function is used to get ip header of a packet,
   * in order to get the tos value of the packet.
   *
   * \param packet is the packet supposed to be resolve.
   *
   * \returns ip header of packet.
   */
  Ipv4Header GetIpv4Header (Ptr<Packet> packet);
  
  /**
   * \the variable indicate the max size of queue.
   */
  uint32_t m_limit;   
  
  /**
   * \the variable indicate the link rate value used in WFQ algorithm.
   */
  uint64_t m_linkRate;  
  
  /**
   * \the variable indicates the ECN threshold of queue.
   */
  float m_threshold;  
  
  /**
   * \the variable indicates the virtual finish time of the first packet in different inner queue.
   */
  std::vector<double> m_finish;  
  
  /**
   * \the variable indicates the virtual finish time of previous packet in different inner queue.
   */
  std::vector<double> m_finish_pre;  
  
  /**
   * \the variable indicates the arrive time of packet of different inner queue.
   */
  std::vector<std::vector<double> > m_now;  
  
  /**
   * \the variable indicates the packet size that arrive to different inner queue.
   */
  std::vector<std::vector<uint32_t> > m_size;  
  
  /**
   * \the variable is the queue that only for protocol packets.
   */
  std::queue<Ptr<QueueItem> > m_control;  
  
  /**
   * \the variable is used to store the mapping rule of tos and queue id.
   */
  std::map<uint8_t, uint8_t> m_map;  
  
}; // class H_WFQQueue

}  // namespace ns3

#endif /* H_WFQQUEUE_H */
